using System;
using System.Collections.Generic;
using System.Text;
using Deepcode.Flux.Core.Systems.Security;
using Deepcode.Flux.Core.Services.Configuration;
using System.Web;

namespace Deepcode.Flux.Core.Services.Security
{
	public class AdministrationSecurity
	{
		/// <summary>
		/// Returns the AdminSecuritySession associated with the current authentication
		/// </summary>
		/// <returns></returns>
		public static AdministrationSecuritySession GetSession()
		{
			HttpContext c = HttpContext.Current;
			if( c == null ) return null;
			if( c.Session == null ) return null;
			object adminObject = c.Session["FluxUser"];
			
			// Check if we have a session object
			if( adminObject == null )
			{
				// Create session based on current credentials
				// See if user is authenticated
				if( ! c.User.Identity.IsAuthenticated ) return null;
				AdministrationUser u = null;
				// How is Flux authenticating ?
				if( FluxConfig.Authentication == FluxAuthenticationMode.FORMS )
				{
					if( c.User.Identity is System.Web.Security.FormsIdentity )
						u = ( new AdministrationUsers()).GetUserByEmail( c.User.Identity.Name );
				}
				else
				{
					if( c.User.Identity is System.Security.Principal.WindowsIdentity )
						u = (new AdministrationUsers()).GetUserByNTName( c.User.Identity.Name );
				}
				
				if( u == null ) return null;

				AdministrationSecuritySession assObject = new AdministrationSecuritySession();
				assObject.PK_ID = u.PK_ID;
				assObject.Identity = c.User.Identity.Name;
				assObject.Email = u.EMailAddress;
				assObject.NT_Username = u.NT_Username;
				assObject.RealName = u.RealName;
				assObject.IsSuperUser = u.IsSuperUser;
				assObject.Groups = u.Groups;
				assObject.Permissions = GetUsersPermissions( u );
				c.Session["FluxUser"] = assObject;
				
				// Login complete, log the event
				Deepcode.Flux.Core.Systems.Audit.SystemEvents ev = new Deepcode.Flux.Core.Systems.Audit.SystemEvents();
				ev.Raise(
					Deepcode.Flux.Core.Systems.Audit.EventSeverity.Information,
					Deepcode.Flux.Core.Systems.Audit.EventType.Security,
					assObject.PK_ID,
					"Flux",
					"Security Login",
					"User ({0}) Logged in ({1})", assObject.Identity, assObject.RealName);
				
				return assObject;
			}
			else
			{
				// adminObject represents a good object, ensure it's for the same identity
				AdministrationSecuritySession assObject = (AdministrationSecuritySession) adminObject;
				return assObject;
			}
		}
		/// <summary>
		/// Utility function which takes a User object and loads an array of permissions
		/// that the user has associated with them.
		/// </summary>
		/// <param name="u"></param>
		/// <returns></returns>
		private static string [] GetUsersPermissions( AdministrationUser u )
		{
			List<string> list = new List<string>();
			foreach( AdministrationGroup g in u.Groups )
				foreach( AdminGroupPermission p in g.Permissions )
					if( ! list.Contains( p.Permission )) 
						list.Add( p.Permission );

			return list.ToArray();
		}

		/// <summary>
		/// Removes the session information from the session.
		/// </summary>
		public static void ClearSession()
		{
			HttpContext c = HttpContext.Current;
			c.Session.Remove("FluxUser");
		}
		/// <summary>
		/// Returns true/false if the user has the permissionCode specified.
		/// If PermissionCode is blank, will just ensure the user exists in the
		/// user database as well as being a valid authentication....
		/// </summary>
		/// <param name="PermissionCode"></param>
		/// <returns></returns>
		public static bool UserHasPermission( string PermissionCode )
		{
			AdministrationSecuritySession user = GetSession();
			if( user == null ) return false;
			if( user.IsSuperUser ) return true;
			if( PermissionCode == "" ) return true;

			foreach( string p in user.Permissions )
				if( p.ToUpper() == PermissionCode.ToUpper() ) return true;

			return false;
		}
		/// <summary>
		/// Returns true/false depending on whether this
		/// user is a member of the GroupID passed in or not
		/// </summary>
		/// <param name="GroupID"></param>
		/// <returns></returns>
		public static bool IsMemberOf( int GroupID )
		{
			AdministrationSecuritySession user = GetSession();
			if( user == null ) return false;
			if( user.IsSuperUser ) return true;
			if( GroupID == -1 ) return true;
			
			foreach( AdministrationGroup g in user.Groups )
				if( g.PK_ID == GroupID ) return true;

			return false;
		}
		/// <summary>
		/// Returns true/false depending on whether this
		/// user is a member of the group name passed in or not.
		/// </summary>
		/// <param name="GroupName"></param>
		/// <returns></returns>
		public static bool IsMemberOf( string GroupName )
		{
			AdministrationSecuritySession user = GetSession();
			if( user == null ) return false;
			if( user.IsSuperUser ) return true;
			if( GroupName == "" ) return true;
			
			foreach( AdministrationGroup g in user.Groups )
				if( g.GroupName == GroupName ) return true;

			return false;
		}
		/// <summary>
		/// Returns true/false depending on whether this
		/// user is a member of one of the groupID's passed
		/// in in CSV format. If GroupList is an empty string
		/// this will return true, otherwise the user must be
		/// a member of at least one of the groups for this 
		/// function to return true.
		/// </summary>
		/// <param name="GroupList"></param>
		/// <returns></returns>
		public static bool IsMemberOfOneGroupID( string GroupList )
		{
			AdministrationSecuritySession user = GetSession();
			if( user == null ) return false;
			if( user.IsSuperUser ) return true;
			if( GroupList == "" ) return true;

			string [] gids = GroupList.Split(',');
			foreach( string gid in gids )
			{
				int igid = -1;
				try{ igid = Int32.Parse( gid ); }
				catch{ igid = -1; };

				if( igid != -1 )
					if( IsMemberOf( igid )) return true;
			}

			return false;
		}
		/// <summary>
		/// Returns true / false if the user is a member of at least one
		/// of the group names passed in as a CSV list.
		/// </summary>
		/// <param name="GroupNameList"></param>
		/// <returns></returns>
		public static bool IsMemberOfOneGroupName( string GroupNameList )
		{
			AdministrationSecuritySession user = GetSession();
			if( user == null ) return false;
			if( user.IsSuperUser ) return true;
			if( GroupNameList == "" ) return true;

			string [] gnames = GroupNameList.Split(',');
			foreach( string gname in gnames )
			{
				if( gname != "" )
					if( IsMemberOf( gname )) return true;
			}

			return false;
		}
		/// <summary>
		/// Returns true if the current user is marked as a super user
		/// </summary>
		/// <returns></returns>
		public static bool IsSuperUser()
		{
			AdministrationSecuritySession user = GetSession();
			if( user == null ) return false;
			if( user.IsSuperUser ) return true;
			return false;
		}
	}
}
